Title Banner

Previous Book Contents Book Index Next

Inside Macintosh: OpenDoc Cookbook / Part - Appendixes
Appendix A - OpenDoc Utilities


Temporary Objects (TempObj)

This section describes the template utilities defined in the files TempObj.h and TempObj.cpp. These utilities provide exception-safe temporary object references, and they handle reference counting automatically.

These are simple template classes that act as a transparent wrapper around an OpenDoc object pointer. The temporary object can be used wherever a pointer to the OpenDoc object would be used. When the temporary object goes out of scope, the object it wraps is either deleted or released (depending on the temporary object class used).

Need for Temporary Objects

When writing OpenDoc-based code, you often need to create temporary objects that later need to be freed or to acquire temporary references to reference-counted objects that later need to be released. In these situations, it is easy to forget to free the object or release the reference. It is also possible for an exception to be thrown while the temporary is active, in which case you can't free the object or release the reference unless you include more complicated exception-handling in your code. In these cases, it is easy to create a memory leak or reference-counting error.

The temporary objects defined in the temporary-objects utility are implemented as stack-based C++ objects whose destructors are called automatically whenever they go out of scope, either by exiting a block or via an exception. This scheme is implemented in the exception-handling utility as the Destructo class, from which the temporary object template classes inherit.

Using Temporary Objects

To use this utility, just include the file TempObj.h in your source files and link TempObj.cpp into your libraries. This gives you access to the following classes:

TempODFrame
TempODPart
TempODShape
TempODStorageUnit
TempODTransform
TempODWindow

TempODFocusSetIterator
TempODFrameFacetIterator

Note
Iterators are not reference counted, so the classes TempODFocusSetIterator and TempODFrameFacetIterator delete the iterator object at the end instead of releasing it.
If your compiler supports C++ templates, you can define a symbol _USE_TEMPLATES_ before including TempObj.h. This will ensure that the header uses templates to implement these classes. This might make the implementation more efficient, and it also makes it much easier to extend the mechanism to new classes. If you can't or don't want to use templates, don't define this symbol; the default is that the classes are implemented without using templates.

Pitfalls

The biggest mistake you can make in using this utility is forgetting that the object is always released. This can cause a problem if you need to use the object as the return value of a function:

ODShape *snod( ODFrame *frame ) {
   TempODShape s = frame->GetFrameShape(ev,kODNULL);
   DoSomething(s);
   return s;
}
The ODShape is released before it's returned, when the destructor of s is called. This is bad news, since the function will return either a pointer to a deleted object or to an object whose reference count is one too low. Either case is likely to cause a crash.

It's still nice to use a TempODShape in this function, for safety in case DoSomething throws an exception. You just want to tell s not to release itself when it's being returned. You can do this by setting the shape to kODNULL before returning it:

ODShape *snod( ODFrame *frame ) {
    TempODShape s = frame->GetFrameShape(ev,kODNULL);
    DoSomething(s);
    ODShape *temp = s;
    s = kODNULL;         // s will not be released by the destructor now
    return temp;
}
Of course, this is a kludge in that you have to store the value of s in a temporary variable to keep it from being lost. Instead, you can use a convenience method called DontRelease that will set the reference to null but return its previous value:

ODShape *snod( ODFrame *frame ) {
    TempODShape s = frame->GetFrameShape(ev,kODNULL);
    DoSomething(s);
    return s.DontRelease();      // Note that "." is used, not "->"}

Using Temporary Iterators

The temporary-objects utility contains some extra classes that are temporary objects for OpenDoc iterator classes. In addition to managing the automatic deletion of the iterator object itself, they also simplify the process of using the iterator and shrink the resulting code. The following example illustrates use of these temporary iterator classes:

extern void DoSomethingWith( ODSnod* );
extern void OrSomethingWith( ODSnod* );
...
ODBazz *bazz;
...
for( TempODSnodIterator iter(ev,bazz); iter.Current(); iter.Next() ) 
{
DoSomethingWith(iter);
OrSomethingWith(iter.Current());
}
Within the loop you can use iter.Current() or just iter to refer to the current object to which the iterator is pointing. You can also use the following syntax to control the iteration loop, because the iterator itself can be used as a synonym for its current object and the ++ operator is the same as calling Next:

for( TempODSnodIterator iter(ev,bazz); iter; iter++ )

Adding New Temporary Classes

There are other OpenDoc classes for which you might want to have temporary objects available. You can define your own temporary object classes using the temporary-objects utility. This is especially easy if your compiler supports templates.

Adding New Classes Using Templates

If you're using templates (by defining _USE_TEMPLATES_ before including TempObj.h), you can declare a temporary reference to any type of reference-counted object by using the class TempRef<className> in the following manner:

TempRef<ODDraft> su = doc->AcquireDraft(ev);
You can also use temporary instances of objects that are not reference counted by using TempObj<class> in the following manner:

TempObj<ODPeanutIterator> iter = peanut->GetIterator(ev);

Adding New Classes Without Using Templates

If you're not using templates, you'll need to do some more work, adding several weird looking #define and #include statements. You can add these to the existing TempObj files, or put them in your own files. To add your own temporary class to the TempObj files, perform the following steps:

  1. Open TempObj.h and find the correct location.
    Scroll down to the comment that reads // Instantiations of TempObj and TempRef. Add your own if necessary. Under the line reading #else /* not _USE_TEMPLATES_*/, find a series of groups of lines, each group of which looks like this:

    #define _T_    ODFrame
    #define _C_ TempODFrame
    #include "TempRef.th"

  2. Add another one of these groups.
    You can do this in TempObj.h or in a separate header of your own. Change _T_ to the OpenDoc class for which you want to make a temporary class. Change _C_ to the name of the temporary-reference class. If the OpenDoc class is not reference counted, include TempObj.th instead of TempRef.th.

  3. Open TempObj.cpp and find the correct location.
    Scroll down to the comment that reads // Define the non-inline methods of the various template classes. Below find another list of #define and #include statements like the ones shown above.

  4. Add another of these groups.
    You add another group in the same manner as in TempObj.h.

  5. Recompile TempObj.cpp.
    If you put the declarations in a separate utility library and not directly in your project, you'll need to build the library first. If TempObj.h is precompiled, the first thing you must do is rebuild the precompiled header.

Type-Checking Errors

If, after adding a new class, you get a type-mismatch error in TempObj.h (probably at line 139) or in TempObj.th or TempRef.th, this indicates that you are trying to use TempObj with a class that is not a subclass of ODObject, or TempRef with a class that is not a subclass of ODRefCntObject. This mismatch can happen even if the class is correct if the compiler hasn't seen the declaration of the class before the declaration of the temporary. In other words, the following is wrong:

class ODSnod;
TempRef<ODSnod> ref = ......;
#include "ODSnod.h"
At the time that the compiler instantiates the template for ODSnod, it does not know anything about the class, such as whether it is a subclass of ODRefCntObject, so it will therefore report type-checking errors. You can avoid this problem by including the header for ODSnod before using the TempRef class.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
16 JUL 1996




Navigation graphic, see text links

Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help